"""
loguru 封装类，导入即可直接使用
"""

import sys
import datetime
import loguru
from pathlib import Path
import os
import yaml
import inspect
from glob import glob
from typing import Any, Dict


class Logger(object):
    def __init__(self):
        self.__config: Dict[str, Any] = {}
        self.__max_log_size: int = 10
        self.__logger: loguru.Logger = loguru.logger
        self.__file_log_directory: Path = Path()

    # 使用 yml 配置文件
    def set_config(self, config_path) -> bool:
        # 获取调用栈的上一级帧
        caller_frame = inspect.stack()[1]
        # 从帧对象中获取文件名（即文件A的路径）
        caller_path = Path(caller_frame.filename)

        if not os.path.exists(config_path):
            raise FileNotFoundError(f"配置文件不存在 : {config_path}")

        with open(config_path, "r", encoding="utf-8") as f:
            self.__config = yaml.safe_load(f)

        # 清空所有设置
        loguru.logger.remove()

        # 控制台输出
        console_log_config = self.__config["ConsoleLog"]
        if console_log_config["is_enable"]:
            loguru.logger.add(
                # 控制台打印
                sys.stderr,
                format="[<green>{time:YYYY-MM-DD HH:mm:ss:SSS}</green> {level:<8}| "  # <颜色>时间
                #    "{process.name} | "  # 进程名
                #    "{thread.name} | "  # 进程名
                "<cyan>{file.path}</cyan>"  # 文件名
                ":<cyan>{line}</cyan> | "  # 行号
                "<level>{message}</level>",  # 日志内容
                level=self.__config["ConsoleLog"]["level"],
                # 防止在生产环境中泄露敏感数据
                # backtrace=False,
                # diagnose=False,
            )

        # 文件保存
        file_log_config = self.__config["FileLog"]
        if file_log_config["is_enable"]:
            if file_log_config["file_directory"] is None:
                # 默认路径, 在调用函数文件的路径创建一个 log 文件夹
                self.__file_log_directory = caller_path.parent / "log"
            else:
                self.__file_log_directory = Path(file_log_config["file_directory"])

            # 日志按运行的文件名创建文件夹
            # self.__file_log_directory = Path(
            #     self.__file_log_directory, caller_path.stem
            # )

            if "max_log_size" in file_log_config:
                self.__max_log_size = file_log_config["max_log_size"]

            # 确保目录存在
            if not os.path.exists(self.__file_log_directory):
                os.makedirs(self.__file_log_directory)
            else:
                self.remove_log()

            # 全部的日志路径,以日期命名
            # file_log_path = Path(
            #     self.__file_log_directory,
            #     "{}.log".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
            # )
            file_log_path = self.__file_log_directory / f"{datetime.date.today()}.log"

            loguru.logger.add(
                # 保存的路径
                sink=file_log_path,
                # 日志创建周期
                rotation=file_log_config["rotation"],
                # 保存时间
                retention=file_log_config["retention"],
                # 文件的压缩格式
                # compression=None,
                # compression="zip",
                # 编码格式
                encoding="utf-8",
                # 支持异步存储
                enqueue=True,
                # 输出格式
                format="[{time:YYYY-MM-DD HH:mm:ss:SSS} {level:<8} | {file.path}:{line}]  {message}",
                level=file_log_config["level"],
                # 防止在生产环境中泄露敏感数据
                # backtrace=False,
                # diagnose=False,
            )

        return True

    def remove_log(self):
        """
        日志文件按创建时间倒序排列, max_log_size 内的文件保留, 其余删除
        """
        if not os.path.exists(self.__file_log_directory):
            self.__logger.error(
                f"日志目录不存在: {self.__file_log_directory}, 无法删除日志文件"
            )
            return

        log_filelist = glob(os.path.join(self.__file_log_directory, "*.log"))

        # 根据文件的创建时间排序
        log_filelist.sort(key=os.path.getctime, reverse=True)

        max_bytes = self.__max_log_size * 1024**2
        accumulated_size = 0
        index = 0  # 防止 log_filelist 为空时候未初始化报错
        for index, file_path in enumerate(log_filelist):
            file_size = os.path.getsize(file_path)
            # 累计文件总大小超过阈值退出,遍历过的文件保留,其他删除
            accumulated_size += file_size
            if accumulated_size > max_bytes:
                break

        # 保留超过阈值的最后一个文件
        index += 1

        # 删除超出保留数量的文件
        for file_to_delete in log_filelist[index:]:
            try:
                os.remove(file_to_delete)
            except Exception as e:
                loguru.logger.error(f"删除日志文件失败: {file_to_delete} - {str(e)}")

    def __getattr__(self, attr):
        """将未定义的属性访问转发给实际的 logger 对象"""
        return getattr(self.__logger, attr)


"""
# 实例化日志类
"""
logging = Logger()


if __name__ == "__main__":
    # 初始化日志配置
    logging.set_config("core/utils/logger_samples/log_cfg.yaml")

    import time

    i = 0
    while True:
        i += 1
        logging.info(f"输出信息{i}")
        time.sleep(1)

    # 日志输出 0-10000, 得出日志输出时间,然后退出
    # import time

    # # 记录开始时间
    # start_time = time.time()

    # # 日志输出 0 到 10000
    # for i in range(10001):
    #     logging.trace(f"跟踪代码: {i}")

    # # 记录结束时间
    # end_time = time.time()

    # # 计算总时间
    # total_time = end_time - start_time

    # # 输出总时间
    # logging.info(f"日志输出总时间: {total_time} 秒")

    # # 退出程序
    # sys.exit(0)

    logging.trace("跟踪代码")
    logging.debug("调试代码")
    logging.info("输出信息")
    logging.success("输出成功")
    logging.warning("错误警告")
    logging.error("代码错误")
    logging.critical("崩溃输出")
    logging.exception("log 异常")

    """
    在其他.py文件中,只需要直接导入已经实例化的logger类即可
    例如导入访视如下：
    from core.utils.logging import logging
    然后直接使用logger即可
    """
    logging.info("----原始测试----")

    def func(a, b):
        return a / b

    def nested(c):
        try:
            func(5, c)
        except ZeroDivisionError:
            logging.exception("What?!")

    nested(0)
